package com.xlh.controller.course;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xlh.common.Result;
import com.xlh.common.ResultEnum;
import com.xlh.constant.UserConstant;
import com.xlh.dao.user.ext.UserClassMapperExt;
import com.xlh.dao.user.ext.UserMapperExt;
import com.xlh.dto.course.*;
import com.xlh.dto.system.ResourceRelationDTO;
import com.xlh.dto.user.ClassCourseDTO;
import com.xlh.dto.user.ClassDTO;
import com.xlh.dto.user.UserInfoDTO;
import com.xlh.enums.ResourceRelationTypeEnum;
import com.xlh.enums.ResourcesTypeEnum;
import com.xlh.enums.course.AuthorityOperatingTypeEnum;
import com.xlh.enums.course.CourseStatusEnum;
import com.xlh.enums.courseTest.CheckEnum;
import com.xlh.enums.courseTest.QuestionOriginEnum;
import com.xlh.enums.user.ClassStatusEnum;
import com.xlh.enums.user.RoleEnum;
import com.xlh.param.course.*;
import com.xlh.pojo.course.Course;
import com.xlh.pojo.user.UserClass;
import com.xlh.security.SpringSecurityUserInfoHolder;
import com.xlh.security.UserInfoHolder;
import com.xlh.service.check.CheckService;
import com.xlh.service.course.ChapterService;
import com.xlh.service.course.CourseService;
import com.xlh.service.courseTest.PaperAnswerSheetService;
import com.xlh.service.system.SystemResourceService;
import com.xlh.service.user.ClassService;
import com.xlh.service.user.UserService;
import com.xlh.util.BeanUtil;
import com.xlh.util.FileUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 课程
 * <p>
 * Created by lx on 2019/1/25.
 */
@Api(tags = "CourseController", description = "课程")
@RestController
@RequestMapping("/course")
public class CourseController {

    @Autowired
    private CourseService courseService;

    @Autowired
    private ClassService classService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserClassMapperExt userClassMapperExt;

    @Autowired
    private ChapterService chapterService;

    @Autowired
    private UserInfoHolder userInfoHolder;

    @Autowired
    private PaperAnswerSheetService paperAnswerSheetService;

    @Autowired
    private SystemResourceService resourceService;

    @Autowired
    private CheckService checkService;

    @Value("${resources.root-dir}")
    private String path;

    @ApiOperation("查询某课程基本信息")
    @GetMapping("/{id}")
    @PreAuthorize("permitAll()")
    public Result<CourseBasicDTO> getCourse(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @Autowired SpringSecurityUserInfoHolder userInfoHolder) {

        // 获取课程基本信息
        CourseBasicDTO course = courseService.getCourse(id);

        // 获取课程大纲资源
        if (userInfoHolder.isTeacher() || userInfoHolder.isAdmin()) {
            ResourcesTypeEnum typeEnum = ResourcesTypeEnum.COURSE_OUTLINE;
            List<ResourceRelationDTO> resource = resourceService.getResourceRelationInfo(
                    Lists.newArrayList(id), Lists.newArrayList(typeEnum.getCode()),
                    null, ResourceRelationTypeEnum.COURSE.getCode());
            if (CollectionUtils.isNotEmpty(resource)) {
                // 读取资源内容
                List<ResourceDTO> resourceDTOS = BeanUtil.batchTransform(ResourceDTO.class, resource);
                resourceDTOS = courseService.readContent(resourceDTOS, typeEnum);
                course.setCourseOutline(StringUtils.isNotBlank(resourceDTOS.get(0).getContent()) ? true : false);
            }
        }

        return Result.success(course);
    }

    @ApiOperation("查询某课程的教师信息")
    @GetMapping("/{id}/user")
    @PreAuthorize("@permissionValidator.isTeacherOrStudent()")
    public Result<List<UserInfoDTO>> getCourseTeacher(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id) {
        return Result.success(courseService.getCourseTeachers(id, null));
    }

    @ApiOperation("获取教师教授某课程的班级列表ztree模式")
    @GetMapping("/{id}/search/list-class")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<List<ClassZtreeDTO>> queryCourseClassList(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @RequestParam(defaultValue = "false", required = false) @ApiParam(value = "状态") Boolean allFlag,
            @RequestParam(defaultValue = "true", required = false)
            @ApiParam(value = "默认班级") Boolean defaultClassFlag) {
        return Result.success(classService.queryClassCourse(id, allFlag, defaultClassFlag));
    }


    @ApiOperation("获取教师教授某课程的班级列表")
    @PostMapping("/{id}/search/class")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<List<Long>> queryCourseClass(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @RequestBody @ApiParam(value = "参数", required = true) @Valid ClassCourseParam param) {
        ClassStatusEnum statusEnum = ClassStatusEnum.getByMessage(param.getStatus());
        List<ClassDTO> classDTOS = classService.listClassCourse(id, param.getGrade(),
                statusEnum == null ? null : statusEnum.isCode(), param.getName());
        return Result.success(classDTOS.stream().map(ClassDTO::getId).collect(Collectors.toList()));
    }

    @ApiOperation("获取教师教授某课程的班级列表")
    @GetMapping("/{id}/list-class")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<List<ClassDTO>> queryCourseClass(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @RequestParam(required = false) @ApiParam(value = "年级") String grade,
            @RequestParam(required = false)
            @ApiParam(value = "是否结课 可不传值 true：已结课 false：未结课") Boolean endFlag) {

        // 获取课程的班级集合
        List<ClassDTO> classDTOS = classService.listClassCourse(
                id, userInfoHolder.getUserId(), grade, endFlag, null);

        if (classDTOS == null) {
            return Result.error(ResultEnum.COURSE_NOT_OWNER);
        }
        if (CollectionUtils.isEmpty(classDTOS)) {
            return Result.error(ResultEnum.NOT_FOUND);
        }

        return Result.success(classDTOS);
    }

    @ApiOperation("获取当前用户的课程状态")
    @GetMapping("/{id}/user-status")
    @PreAuthorize("@permissionValidator.isTeacherOrStudent()")
    public Result<String> queryUserCourseStatus(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id) {
        return Result.success(courseService.queryUserCourseStatus(id).name());
    }

    @ApiOperation("修改默认班级")
    @PutMapping("/{id}/class/{classId}/default")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result updateDefaultClass(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @PathVariable("classId") @ApiParam(value = "班级id", required = true) Long classId) {
        classService.updateDefaultClass(id, classId);
        return Result.success();
    }

    @ApiOperation("获取某课程班级统计信息")
    @GetMapping("/{id}/class/{classId}/statistics")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<CourseClassStatisticsDTO> queryCourseClassStatistics(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @PathVariable("classId") @ApiParam(value = "班级id", required = true) Long classId) {

        List<ClassCourseDTO> classCourses = classService.queryClassCourse(Lists.newArrayList(classId));
        if (CollectionUtils.isEmpty(classCourses)) {
            return Result.error(ResultEnum.SERVER_ERROR, "班级不存在");
        }

        CourseClassStatisticsDTO result = BeanUtil.transform(CourseClassStatisticsDTO.class, classCourses.get(0));
        result.setStatus(ClassStatusEnum.getByCode(result.getEnded()).getMessage());

        //Map<Long, Long> userCountMap = userService.getCountByClassId(Lists.newArrayList(classId));
        // 关联查询未删除的学生
        List<UserClass> notDeleteUserClass = userClassMapperExt.findNotDeleteUserClass(classId);

        if (CollectionUtil.isNotEmpty(notDeleteUserClass)) {
            result.setStudentCount(Long.valueOf(notDeleteUserClass.size()));
        }

        Map<Long, List<ClassCourseDTO>> map = Maps.newHashMap();
        map.put(id, Lists.newArrayList(new ClassCourseDTO(classId, result.getGrade(), result.getEnded())));

        // 获取当前教师的待审批随堂练习
        StatisticsDTO practiceCheckCount = checkService.getClassCheckCount(map, CheckEnum.PRACTICE);
        result.setUnreviewedPracticeCount(practiceCheckCount.getCount() == null ?
                0L : practiceCheckCount.getCount());

        // 获取当前教师的待审批实验报告
        StatisticsDTO experimentCheckCount = checkService.getClassCheckCount(map, CheckEnum.EXPERIMENT);
        result.setUnreviewedReportCount(experimentCheckCount.getCount() == null ?
                0L : experimentCheckCount.getCount());

        // 获取当前教师的待审批试卷
        StatisticsDTO paperDTO = paperAnswerSheetService.getClassCheckCount(map);
        result.setUnreviewedTestPaperCount(paperDTO.getCount() == null ?
                0L : paperDTO.getCount());

        return Result.success(result);
    }

    @ApiOperation("显示某课程下的资源显示控制")
    @PostMapping("/{id}/resource-right")
    @PreAuthorize("@permissionValidator.isTeacher() and @permissionValidator.isCourseOwner(#courseId)")
    public Result<List<ResourceAuthorityDTO>> queryResourceAuthority(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long courseId,
            @RequestParam @ApiParam(value = "操作类型 1:对课程 2：对章节", required = true) Integer operatingType,
            @RequestParam(required = false) @ApiParam(value = "章节id") Long chapterId,
            @RequestBody @ApiParam(value = "获取的参数", required = true) @Valid List<ResourceAuthorityParam> params) {

        Map<ResourcesTypeEnum, List<String>> typeEnumListMap = params.stream()
                .collect(Collectors.toMap(o -> ResourcesTypeEnum.getByCode(o.getResourcesType()),
                        ResourceAuthorityParam::getNames));

        AuthorityOperatingTypeEnum typeEnum = AuthorityOperatingTypeEnum.getByCode(operatingType);
        Long objId = typeEnum == AuthorityOperatingTypeEnum.COURSE ? courseId : chapterId;

        Course course = courseService.getCourseById(courseId);

        List<ResourceAuthorityDTO> resourceAuthorityDTOS = chapterService.queryResourceAuthority(course.getUserId(),
                typeEnumListMap, typeEnum,
                Lists.newArrayList(objId)).get(objId);
        if (CollectionUtils.isEmpty(resourceAuthorityDTOS)) {
            return Result.error(ResultEnum.NOT_FOUND);
        }

        return Result.success(resourceAuthorityDTOS);
    }

    @ApiOperation("修改某课程下的资源下载/显示控制")
    @PutMapping("/{id}/resource-right")
    @PreAuthorize("@permissionValidator.isTeacher() and @permissionValidator.isCourseOwner(#courseId)")
    public Result updateResourceAuthority(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long courseId,
            @RequestParam @ApiParam(value = "操作类型 1:对课程 2：对章节", required = true) Integer operatingType,
            @RequestBody @ApiParam(value = "修改的参数", required = true)
            @Valid List<UpdateResourceAuthorityParam> params) {

        chapterService.updateResourceAuthority(courseId, params, AuthorityOperatingTypeEnum.getByCode(operatingType));
        return Result.success();
    }

    @ApiOperation("创建课程")
    @PostMapping
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<Long> createCourse(
            @RequestBody @ApiParam(value = "创建的参数", required = true) @Valid CourseParam param) {
        return Result.success(courseService.createCourse(param));
    }

    @ApiOperation("修改课程")
    @PutMapping("/{id}")
    @PreAuthorize("@permissionValidator.isAdmin() or @permissionValidator.isCourseOwner(#courseId)")
    public Result updateCourse(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long courseId,
            @RequestBody @ApiParam(value = "修改的参数", required = true) @Valid CourseParam param) {
        courseService.updateCourse(courseId, param);
        return Result.success();
    }

    @ApiOperation("删除课程")
    @DeleteMapping("/{id}")
    @PreAuthorize("@permissionValidator.isAdmin() or @permissionValidator.isCourseOwner(#courseId)")
    public Result updateCourse(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long courseId,
            @RequestParam(required = false)
            @ApiParam(value = "错误处理 true：进行删除 null：无错误标识") Boolean errorDealFlag) {
        // 网络管理员删除：数据库真删，超管删除：数据库假删
        boolean logicDeleted = RoleEnum.INTERNET_ADMIN.getRoleCode() == userInfoHolder.getUser().getRole() ?
                false : true;
        courseService.deleteBatchCourse(Lists.newArrayList(courseId), errorDealFlag, logicDeleted, null);
        return Result.success();
    }

    @ApiOperation("修改课程状态")
    @PutMapping("/{id}/status")
    @PreAuthorize("@permissionValidator.isAdmin() or @permissionValidator.isCourseOwner(#courseId)")
    public Result updateCourseStatus(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long courseId,
            @RequestParam @ApiParam(value = "状态 1：保存 2：发布", required = true) Integer status) {
        courseService.updateCourseStatus(courseId, CourseStatusEnum.getByCode(status));
        return Result.success();
    }

    @ApiOperation("获取教师预置课程、自定义课程的章节ztree")
    @GetMapping("/{id}/ztree")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<List<ZtreeDTO>> getCourseChapterByType(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @RequestParam
            @ApiParam(value = "类型 0：自定义 1：预置 见：QuestionOriginEnum", required = true) Integer type) {
        return Result.success(chapterService.getCourseChapterByType(id, QuestionOriginEnum.forCode(type)));
    }

    @ApiOperation("获取预置课程")
    @GetMapping("/preset")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<List<CourseDTO>> queryPresetCourse() {
        return Result.success(courseService.listCourse(
                Lists.newArrayList(CourseStatusEnum.SHARED.getCode()),
                true, true, null, null));
    }

    @ApiOperation("创作课程的数据")
    @GetMapping("/creation")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<List<CourseDTO>> queryCreationCourse() {
        return Result.success(courseService.queryCourseList());
    }

    @ApiOperation("是否允许下载预置资源文件")
    @PostMapping("/preset-resource/download/permission")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<String> presetDownloadPermission(@RequestBody @Valid FileParam param) {
        courseService.checkAndGetFilePath(ResourcesTypeEnum.PRESET_RESOURCE.getCode(), param);
        String uuid = RandomUtil.simpleUUID();
        UserConstant.DOWNLOAD_FILE_MAP.put(userInfoHolder.getUserId() + uuid, param);
        return Result.success(uuid);
    }

    @ApiOperation("下载预置资源文件")
    @GetMapping("/preset-resource/download")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<String> presetDownload(
            HttpServletResponse response, @RequestParam @ApiParam(value = "token", required = true) String token) {

        FileParam param = chapterService.getTokenValueAndRemove(token);
        String filePath = courseService.checkAndGetFilePath(ResourcesTypeEnum.PRESET_RESOURCE.getCode(), param);

        // 下载资源
        try {
            FileUtil.downloadFile(response, filePath, param.getDownloadFileName());
        } catch (Exception e) {
            return Result.error(ResultEnum.SERVER_ERROR);
        }

        return Result.success();
    }

    @ApiOperation("打包/重新打包预置资源包")
    @PostMapping("/{id}/preset-resource")
    @PreAuthorize("@permissionValidator.isAdmin()")
    public Result<String> createOrUpdatePresetResource(@PathVariable("id") Long id) {
        courseService.createOrUpdatePresetResource(id);
        return Result.success();
    }

    @ApiOperation("我的课程详情导航")
    @GetMapping("/{id}/navigation")
    @PreAuthorize("@permissionValidator.isTeacherOrStudent()")
    public Result<List<CourseNavigationDTO>> queryUserNavigation(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id) {
        return Result.success(courseService.getUserNavigation(id));
    }

    @ApiOperation("添加/修改课程分类")
    @PostMapping("/{id}/course-sort")
    @PreAuthorize("@permissionValidator.isAdmin() " +
            "or (@permissionValidator.isTeacher() and @permissionValidator.isCourseOwner(#id))")
    public Result createOrUpdateCourseSort(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @RequestBody @ApiParam(value = "修改的参数", required = true)
            @Valid List<CreateOrUpdateCourseSortParam> params) {
        courseService.createOrUpdateCourseSort(id, params);
        return Result.success();
    }

    @ApiOperation("添加/修改课程章节分类")
    @PostMapping("/{id}/chapter-course-sort")
    @PreAuthorize("@permissionValidator.isAdmin() " +
            "or (@permissionValidator.isTeacher() and @permissionValidator.isCourseOwner(#id))")
    public Result createOrUpdateCourseSortAndChapter(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @RequestBody @ApiParam(value = "修改的参数", required = true)
            @Valid List<CreateChapterCourseSortParam> params) {
        chapterService.createOrUpdateChapterCourseSort(id, params);
        return Result.success();
    }

    @ApiOperation("获取某课程的章节列表")
    @GetMapping("/{id}/chapter-course-sort/chapter-list")
    @PreAuthorize("@permissionValidator.isAdmin() " +
            "or (@permissionValidator.isTeacher() and @permissionValidator.isCourseOwner(#id))")
    public Result<List<ChapterBasicInfoDTO>> listChapter(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id) {
        return Result.success(chapterService.listChapterInfo(id));
    }

    @ApiOperation("获取某课程的章节及课程分类的ztree")
    @GetMapping("/{id}/chapter-course-sort-list")
    @PreAuthorize("@permissionValidator.isAdmin() " +
            "or (@permissionValidator.isTeacher() and @permissionValidator.isCourseOwner(#id))")
    public Result<List<CourseSortDTO>> listChapterCourseSort(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id) {
        return Result.success(chapterService.listChapterCourseSort(id));
    }

    @ApiOperation("添加/编辑课程资源")
    @PostMapping("/{id}/resource")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<String> createOrUpdateResource(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @RequestParam @ApiParam(value = "资源类型", required = true) Integer resourceType,
            @RequestBody @ApiParam(value = "修改资源信息", required = true) CreateResourceParam param) {
        courseService.createOrUpdateResource(id, ResourcesTypeEnum.getByCode(resourceType), param);
        return Result.success();
    }

    @ApiOperation("获取课程资源")
    @GetMapping("/{id}/resource")
    @PreAuthorize("permitAll()")
    public Result<Map<String, ResourceInfoDTO>> queryResource(
            @PathVariable("id") @ApiParam(value = "课程id", required = true) Long id,
            @RequestParam @ApiParam(value = "资源类型", required = true) List<Integer> resourceType) {
        return Result.success(courseService.queryResource(id, ResourcesTypeEnum.getByCodes(resourceType)));
    }


}
